#自动按条件维护数据的更新时间，不需要从数据库查询
require 'active_support/concern'
module UpdateCacheKey
  extend ActiveSupport::Concern

  included do
    include InstanceMethods

    cattr_accessor :cache_key_group, :cache_check_fields, :cache_check_if
    after_save :refresh_update_cache_key
    after_destroy :refresh_update_cache_key
    private :refresh_update_cache_key

  end

  class_methods do
    #自动刷新cache_key
    #参数： group -> 按字段分组，如果为空则为全部数据
    #as -> group的别名，用于一个字段几个key的形式
    # :check => []检查哪些字段修改 or :check => {:only => []}
    # :if => 检查的proc
    def update_cache_key(options)
      group_key = options[:as] || options[:group]
      self.cache_key_group ||= {}
      self.cache_check_fields ||= {}
      self.cache_check_if ||= {}
      self.cache_key_group[group_key] = options[:group]
      option_check = options[:check]
      checks = case option_check
      when Array
        option_check
      when Hash
        option_check[:except] ? self.column_names - option_check[:except].map(&:to_s) : self.column_names & option_check[:only].map(&:to_s)
      when :all
        self.column_names
      else
        []
      end
      self.cache_check_fields[group_key] = checks
      self.cache_check_if[group_key] = options[:if]
    end

    def get_update_cache_key(key = nil, group_id = nil)
      cache_key = "#{self.table_name}_updated_at"
      cache_key << "/#{key}" if key
      cache_key <<  "/#{group_id.to_s}" if group_id
      Rails.cache.fetch(cache_key, :expires_in => 23.hours) {Time.now.to_i}
    end

    def reset_update_cache_key(key = nil, group_id = nil)
      cache_key = self.get_update_cache_key(key, group_id)
      Rails.cache.write(cache_key, Time.now.to_i)
    end
  end

  module InstanceMethods
    def refresh_update_cache_key
      self.cache_key_group.each do |key, group|
        return if self.cache_check_fields.blank?
        if fields = self.cache_check_fields[key].presence
          next unless fields.detect{|f| self.saved_change_to_id.present? || self.destroyed? || self.send("saved_change_to_#{f}?")}
        end
        if self.cache_check_if[key]
          next unless self.destroyed? || self.cache_check_if[key].call(self)
        end
        cache_key = "#{self.class.table_name}_updated_at"
        cache_key << "/#{key}" if key
        cache_key << "/#{(self.send group).to_s}" if group
        Rails.cache.write(cache_key, Time.now.to_i)
      end
    end
  end
end
